home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 January: Mac OS SDK / Dev.CD Jan 97 SDK2.toast / Development Kits (Disc 2) / OpenDoc / OpenDoc Development / Debugging Support / OpenDoc™ Source Code / Messaging / OSL / OSLEvals.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-28  |  28.2 KB  |  1,021 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        OSLEvals.c
  3.  
  4.     Contains:    
  5.  
  6.     Owned by:    Nick Pilch
  7.  
  8.     Copyright:    © 1992 - 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.          <5>     7/27/96    JP        1372873: Backed out marking fix by
  13.                                     undefining MARKING_FIX
  14.          <3>     6/20/96    JP        1323103: Fixed marking (but no definitive
  15.                                     test cases yet)
  16.          <2>     1/15/96    TJ        Cleaned Up
  17.          <6>     6/22/95    NP        1261016: Don't call OSLDiposeToken when
  18.                                     adding tokens to a list.
  19.          <5>     6/20/95    NP        1252761: Restore context around a whose
  20.                                     clause.
  21.          <4>     6/13/95    eeh        1252761: whose clauses reset context
  22.                                     (disabled)
  23.          <3>     1/12/95    jpa        Don't use obsolete Toolbox names [1211211]
  24.          <2>     8/19/94    NP        1181622: Ownership fix.
  25.          <9>      5/5/94    eeh        bug #1160654: fix for SCPP
  26.          <8>      5/2/94    eeh        bug #1160654: various PPC native changes
  27.          <7>     3/23/94    NP        1143046-unitialized local variable.
  28.          <6>    10/18/93    NP        Added mark functions callback support for
  29.                                     OpenDoc.
  30.          <5>    10/11/93    NP        Removed stuff added previously for tokens.
  31.                                     Changed count and compare callback
  32.                                     dispatching.
  33.          <4>     8/18/93    NP        Changed MakeNullToken
  34.          <3>     8/16/93    NP        Adjusted for latest OSL proposal.
  35.          <2>     7/28/93    NP        Mods for new token type, OSLToken.
  36.          <1>     7/21/93    NP        first checked in
  37.  
  38.     To Do:
  39. */
  40.  
  41. #include "OSLPriv.h"
  42. #include <ToolUtils.h>
  43.  
  44. #define UNUSED(x)    ((void) &x)
  45.  
  46. //#define MARKING_FIX
  47.  
  48. #pragma segment AEObjSuppt
  49.  
  50. void
  51. MakeNull( AEDesc *theDesc )
  52. {
  53.     theDesc->descriptorType = typeNull ;
  54.     theDesc->dataHandle = NULL ;
  55. }
  56.     
  57. void
  58. MakeNullToken( OSLToken *theToken )
  59. {
  60.     theToken->descriptorType = typeNull ;
  61. //    theToken->context = 0 ;
  62.     theToken->dataHandle = NULL ;
  63. }
  64.     
  65.  
  66. static OSErr EvalTerm( Term t , DescType exmnClass, OSLToken *objBeingExamined ,
  67.         short appDoesFlags) ;
  68.  
  69.  
  70. /*———————————————————————— EvalCompare ————————————————————————*/
  71.  
  72. /*evaluates a comparison*/
  73.  
  74. static OSErr
  75. EvalCompare( Comparison  c , DescType  exmnClass ,
  76.         OSLToken  *objBeingExamined , short appDoesFlags)
  77. {
  78.     Boolean              compResult ;
  79.     
  80.     OSErr err = noErr ;
  81.     if ( (*c)->redo )
  82.     {
  83.         FailErr( EvalObj( (*c)->obj1, exmnClass, objBeingExamined, 
  84.             appDoesFlags ), err, errExit ) ;        /* eval first object */
  85.         FailErr( EvalObj( (*c)->obj2, exmnClass, objBeingExamined,
  86.             appDoesFlags ), err, errExit ) ;        /* eval second object */
  87.          
  88.          // compare em
  89.          FailErr( NewCallCompareProc( (*c)->oper, (*((*c)->obj1))->objValue,
  90.             (*((*c)->obj2))->objValue, &compResult ), err, errExit  ) ;
  91.         (*c)->value = compResult ;
  92.  
  93.         // set redo flag if either object must redo
  94.         (*c)->redo = (*((*c)->obj1))->objRedo
  95.                 || (*((*c)->obj2))->objRedo ;
  96.     }
  97.  
  98. FAIL_ERR_PROC(err, errExit)
  99.     if ( SetErrDesc( (*c)->theCompInput ) )        // 4/5. So doesn't dispose later */
  100.         (*c)->theCompInput.dataHandle = NULL ; 
  101. END_FAIL_ERR_PROC(err)
  102.  
  103.  
  104.  
  105. } /* EvalCompare */
  106.  
  107.     /*———————————————————————— EvalLogical ————————————————————————*/
  108.  
  109. static OSErr
  110. EvalLogical( Logical l , DescType  exmnClass ,
  111.         OSLToken *objBeingExamined , short appDoesFlags )
  112. {
  113.     Term          thisTerm ;
  114.     Boolean thisTermVal  ;
  115.     Boolean          terminateCond ;
  116.     OSErr err = noErr;
  117.     
  118.     HLock((Handle)l) ;
  119. //    WITH l** DO
  120.     {
  121.         LogicalPtr lp = *l ;
  122.         if ( lp->redo )
  123.         {
  124.         
  125.         if ( lp->logicalOp == kAEAND )
  126.             terminateCond = false ;
  127.         else if ( lp->logicalOp == kAEOR )
  128.             terminateCond = true ;
  129.         else if ( lp->logicalOp != kAENOT )        /* if ( not, don't care what term value is */
  130.             FailErr( errAENoSuchLogical, err, errExit ) ;
  131.         
  132.         /* Grab the first term, then loop through evaluating them.
  133.         kAENot must have exactly one term; OR and AND may have any number,
  134.         including 0. */
  135.         
  136.         thisTerm = lp->firstTerm ;
  137.         if ( (lp->logicalOp == kAENOT)
  138.                 && ((thisTerm == NULL) || ((*thisTerm)->next != NULL)) )
  139.             FailErr( errAEWrongNumberArgs , err, errExit ) ;
  140.         
  141.         while( thisTerm != NULL )
  142.         {
  143.             FailErr( EvalTerm( thisTerm, exmnClass, objBeingExamined,
  144.                     appDoesFlags ), err, errExit ) ;
  145.             thisTermVal = (*thisTerm)->value ;
  146.             lp->redo |= (*thisTerm)->redo ;
  147.         
  148.             if ( thisTermVal == terminateCond )
  149.                 break ;
  150.         
  151.             thisTerm = (*thisTerm)->next ;
  152.         } /* while */
  153.         
  154.         if ( lp->logicalOp == kAENOT )
  155.             lp->value = !thisTermVal ;
  156.         else
  157.             lp->value = thisTermVal ;        // This works for either way out of the loop */
  158.         
  159.         }
  160.     }
  161.     HUnlock((Handle)l);
  162.  
  163. FAIL_ERR_PROC(err, errExit)
  164.     if ( (l != NULL) && (SetErrDesc( (*l)->theLogicalInput )) )                /* 4/5. So doesn't dispose later */
  165.         (*l)->theLogicalInput.dataHandle = NULL ;
  166. END_FAIL_ERR_PROC(err)
  167.  
  168.  
  169. } /*EvalLogical*/
  170.  
  171.     /*———————————————————————— EvalObj ————————————————————————*/
  172.  
  173. OSErr
  174. EvalObj( Object o, DescType  exmnClass, OSLToken *objectBeingExmn,
  175.         short appDoesFlags )
  176. {
  177.     Boolean              ignoreBool ;
  178.     OSErr err = noErr;
  179.     
  180.     UNUSED(appDoesFlags) ;
  181.     
  182.     if ( (*o)->objRedo )
  183.     {
  184.         HLock( (Handle)o ) ;
  185. //        WITH o** DO
  186.         {
  187.             ObjRecordPtr op = *o ;
  188. //            FailErr( iAEDisposeToken( objValue ) ) ;
  189.             FailErr( InternalResolve( o, exmnClass, 
  190.                 objectBeingExmn, &ignoreBool, &op->objValue, &op->objRedo),
  191.                 err, errExit ) ;
  192.         }
  193.         HUnlock((Handle)o);
  194.     }
  195.  
  196. FAIL_ERR_PROC(err, errExit)
  197.     if ( (o != NULL) && (SetErrDesc( (*o)->theObjInput )) )                /* 4/5. So doesn't dispose later */
  198.         (*o)->theObjInput.dataHandle = NULL ; 
  199. END_FAIL_ERR_PROC(err)
  200.  
  201. } /*EvalObj*/
  202.  
  203.  
  204. #define kKeyExmnClass    ((DescType)'exmn')
  205.  
  206.  
  207.  
  208. static OSErr
  209. EvalCompareEvnt( CompareEvent cevt, DescType exmnClass,
  210.         OSLToken *objBeingExamined )
  211. {
  212.     OSLToken prevExmn ;
  213.     AESendMode sendMode = kAEWaitReply ;
  214.     AESendPriority sendPriority = kAENormalPriority;
  215.     AppleEvent reply ;
  216.     DescType returnedType ;
  217.     long actualSize ;
  218.     Boolean trueOrFalse ;
  219.     OSErr err = noErr ;
  220.     
  221.     prevExmn.dataHandle = NULL ;
  222.     reply.dataHandle = NULL ;
  223.  
  224.     FailErr( GetExmn( &prevExmn ), err, errExit ) ; 
  225.     FailErr( SetExmn( objBeingExamined ), err, errExit ) ; 
  226.     
  227.     // send the event
  228.     HLock( (Handle) cevt ) ;
  229.     FailErr( AEPutParamPtr( &(*cevt)->eventWParams, kKeyExmnClass, typeType,
  230.                (Ptr)&exmnClass, sizeof(exmnClass) ), err, errExit ) ;
  231.     FailErr( AESend( &(*cevt)->eventWParams, &reply, sendMode, sendPriority,
  232.             kNoTimeOut, NULL, NULL ), err, errExit ) ;
  233.     HUnlock( (Handle) cevt ) ;
  234.  
  235.     // get the true or false info
  236.     FailErr( AEGetParamPtr( &reply, keyDirectObject, typeBoolean, &returnedType,
  237.             (Ptr)&trueOrFalse, sizeof(trueOrFalse), &actualSize), err, errExit ) ;
  238.  
  239.     (*cevt)->value = trueOrFalse ;
  240.  
  241.     FailErr( SetExmn( &prevExmn ), err, errExit ) ; 
  242.  
  243. FAIL_ERR_PROC(err, errExit)
  244.     if ( prevExmn.dataHandle )
  245.         CIgnoreOSErr( SetExmn( &prevExmn ) ) ; 
  246.     if ( reply.dataHandle )
  247.         IgnoreOSErr( AEDisposeDesc(&reply) ) ; 
  248. END_FAIL_ERR_PROC(err)
  249. }
  250.  
  251.  
  252.  
  253.  
  254.     /*———————————————————————— EvalTerm ————————————————————————*/
  255.  
  256. static OSErr
  257. EvalTerm( Term t , DescType exmnClass, OSLToken *objBeingExamined ,
  258.         short appDoesFlags)
  259. {
  260. //    AEDesc              saveDesc
  261.  
  262.     OSErr err = noErr;
  263.  
  264. //        saveDesc = objBeingExamined ;        */
  265.     HLock((Handle)t);
  266.     if ( (*t)->redo )
  267.     {
  268.         switch ( (*t)->ttype )
  269.         {
  270.             case kCompare :
  271.                 FailErr( EvalCompare( (*t)->u.compar, exmnClass,
  272.                         objBeingExamined, appDoesFlags), err, errExit ) ;
  273.                 (*t)->redo = (*((*t)->u.compar))->redo;
  274.                 (*t)->value = (*((*t)->u.compar))->value ;
  275.                 break ;
  276.  
  277.             case kCompareEvt :
  278.                 FailErr( EvalCompareEvnt( (*t)->u.cEvt, exmnClass, objBeingExamined ),
  279.                         err, errExit ) ;
  280.                 (*t)->redo = (*((*t)->u.cEvt))->redo ;
  281.                 (*t)->value = (*((*t)->u.cEvt))->value ;
  282.                 break ;
  283.  
  284.             case kLogical :
  285.                 FailErr( EvalLogical( (*t)->u.log, exmnClass, objBeingExamined,
  286.                         appDoesFlags), err, errExit ) ;
  287.                 (*t)->redo = (*((*t)->u.log))->redo;
  288.                 (*t)->value = (*((*t)->u.log))->value ;
  289.  
  290.         }
  291.     
  292. //        if ( (*t)->value )
  293. //            objBeingExamined = saveDesc ;
  294. //        else
  295. //            FailErr( iAEDisposeToken( saveDesc ) ) ;
  296.     }
  297.     HUnlock((Handle)t);
  298.  
  299. FAIL_ERR_PROC(err, errExit)
  300.     if ( ( t != NULL) && (SetErrDesc( (*t)->theTermInput )) )        /* 4/5. So doesn't dispose later */
  301.         (*t)->theTermInput.dataHandle = NULL ;
  302. END_FAIL_ERR_PROC(err)
  303.  
  304. } /*EvalTerm*/
  305.  
  306.  
  307. ////////////////////////////////////////////////////////////////////////////////////
  308. //
  309. //        EvalWhose() and its service routines
  310. //
  311. ////////////////////////////////////////////////////////////////////////////////////
  312.  
  313.  
  314. // for the C port, I'm adding this struct to pass the variables that the various
  315. // EvalWhose service routines have access to by virtue of being nested inside
  316. // EvalWhose() in the Pascal version.
  317.  
  318. //CONST
  319. //kNumDescsToAdd == 20 ;            /* descriptors stored in a Handle: when it's full, resize by this number */
  320. //kStoreAllSuccesses == 0 ;    /* special value for numToStore meaning infinite */
  321. //TYPE
  322. typedef AEDesc *DescArrayPtr, **DescArrayHandle ;
  323.  
  324. typedef OSLToken *OSLTokenPtr, **OSLTokenHandle ;
  325.  
  326. typedef struct WHG {            // EvalWhoseGlobals
  327.     OSLToken         tempList ;        // see EvalWhose for some comments about these
  328.     OSLToken         markToken ;                    // vars
  329.     OSLTokenHandle          theDescArrayH ;
  330.     long          nSuccesses ;
  331.     long          numInStorage ;            
  332.     Boolean          isARange ;
  333.     Boolean          hasRelative ;
  334.     Boolean          mark ;
  335.     Boolean          goingBackward ;
  336.     Boolean          mustReturnList ;
  337.     
  338.     Whose w ;            // this is a formal: has to be added too though
  339.     } WHG ;
  340.  
  341.  
  342. static OSErr
  343. DisposeDescArray( OSLTokenPtr startDesc, long nToDispose )
  344. {
  345.     OSLTokenPtr stopDesc ;
  346.     OSErr err = noErr ;
  347.  
  348.     stopDesc = startDesc + nToDispose ;
  349.     while ( startDesc < stopDesc  )
  350.     {
  351.         FailErr( iAEDisposeToken( startDesc ), err, errExit ) ;
  352.         ++startDesc ;
  353.     }
  354.  
  355. FAIL_ERR_PROC(err, errExit)
  356. END_FAIL_ERR_PROC(err)
  357. }
  358.  
  359. #ifdef MARKING_FIX
  360. static OSErr
  361. InitMarking( DescType containerClass, OSLToken container, WHG *wg )
  362. {
  363.     OSLContext    curContext;
  364.     short        appDoesFlags;
  365.     OSErr        err;
  366.     
  367.     FailErr (GetCurrentContext(&curContext), err, errExit);
  368.     FailErr (GetAppDoesFlags(&curContext, &appDoesFlags), err, errExit);
  369.     wg->mark = (appDoesFlags & kAEIDoMarking) != 0 ;
  370.     if ( wg->mark )
  371.     {
  372.         FailErr( NewCallGetMarkToken( container, containerClass, &wg->markToken ),
  373.                 err, errExit ) ;
  374.     }
  375.     else
  376.     {
  377.         wg->theDescArrayH = (OSLTokenHandle)NewHandle( 0 ) ; /* sizeof(AEDesc) )) ;*/
  378.         FailErr( MemError(), err, errExit ) ;
  379.     }
  380.         
  381.     
  382. FAIL_ERR_PROC(err, errExit)
  383. END_FAIL_ERR_PROC(err)
  384. }    // InitMarking
  385. #endif
  386.  
  387. static OSErr
  388. RedoListOrMark( long realStart, long realStop, WHG *wg )
  389. {
  390.     long                 temp ;
  391.     long                  sizeSought ;
  392.     OSLTokenPtr          theDescArrP ;
  393.     OSErr err = noErr ;
  394.  
  395.     if ( wg->numInStorage < realStop )
  396.         FailErr( errAENoSuchObject, err, errExit ) ; /* was errInvalidOffset */
  397.  
  398.     if ( realStart > realStop )            // 2/18. if we wanted the 20th and there are only 19, error
  399.     {
  400.         if ( wg->isARange && wg->hasRelative
  401.                 && ((*(wg->w))->index.startCase == kAEAny)
  402.                 && ((*(wg->w))->index.stopCase == kAEAny) )        // special case for
  403.                                                                 // any to any range 
  404.         {
  405.             temp = realStart ;
  406.             realStart = realStop ;
  407.             realStop = temp ;
  408.         }
  409.         else if ( !(wg->mustReturnList) )
  410.             FailErr( errAENoSuchObject, err, errExit ) ;    // was errInvalidOffset
  411.     }
  412.  
  413.     if ( wg->mark )
  414.     {
  415.         FailErr( NewCallAdjustMarks( realStart, realStop, wg->markToken ),
  416.                 err, errExit ) ;
  417.     }
  418.     else
  419.     {            // ok if ( realStart > realStop b/c just disposing null tokens 
  420.         HLock( (Handle)wg->theDescArrayH ) ;
  421.         theDescArrP = *(wg->theDescArrayH) ;
  422.         
  423.         /* First, allow client to dispose of all the tokens we won't include in the result */
  424.         
  425.         if ( realStart > 1 )
  426.             FailErr( DisposeDescArray( theDescArrP, realStart-1 ),
  427.                 err, errExit ) ;
  428.         
  429.         if ( wg->numInStorage > realStop )
  430.             FailErr( DisposeDescArray( &theDescArrP[realStop] ,
  431.                     wg->numInStorage - realStop ), err, errExit ) ;
  432.         
  433.         /* calc the number of bytes the final array of AEDesc ought to contain */
  434.         wg->numInStorage = realStop - realStart + 1 ;
  435.         sizeSought = wg->numInStorage * sizeof(AEDesc) ;
  436.         
  437.         /* shif (t what we want to keep to the start of the block. Don't bother if ( already there.
  438.         No need to check sizeSought>0 b/c BlockMove bails if ( negative. */
  439.         if ( realStart > 1 )
  440.         BlockMove( theDescArrP + realStart - 1, (Ptr)theDescArrP, sizeSought ) ;
  441.         
  442.         HUnlock( (Handle)wg->theDescArrayH ) ;
  443.         SetHandleSize( (Handle)wg->theDescArrayH, sizeSought ) ;
  444.     }
  445.  
  446. FAIL_ERR_PROC(err, errExit)
  447. END_FAIL_ERR_PROC(err)
  448.  
  449. } /* RedoListOrMark */
  450.  
  451.  
  452.  
  453. static OSErr
  454. MarkOrRemember( OSLToken  dToken , long index, DescType containerClass, OSLToken container, WHG *wg  )
  455. {
  456.     long                  offset  ;
  457.     OSErr err = noErr ;
  458.     
  459. #ifdef MARKING_FIX
  460.     if (wg->numInStorage == 0)
  461.         InitMarking(containerClass, container, wg);
  462. #endif
  463.  
  464.     if ( wg->mark )
  465.     {
  466.         FailErr( NewCallMark( dToken, wg->markToken, index ), err, errExit ) ;
  467.     
  468.         /* <eeh> The app has passed me what is most
  469.         likely a fresh descriptor with a unique reference to a relocatable block.
  470.         if ( I don't dispose of it before reusing the variable the heap will fill
  471.         up, yet this may send the wrong message to the app.  I am NOT done with
  472.         the reference to the app's object. */
  473.     }
  474.     else
  475.     {
  476.         if ( wg->goingBackward )                /* we want to store in reverse order */
  477.             offset = 0 ;
  478.         else
  479.             offset = GetHandleSize( (Handle)wg->theDescArrayH ) ;
  480.         
  481.         Munger( (Handle)wg->theDescArrayH, offset, NULL, 0, &dToken, sizeof( dToken ) ) ;
  482.         FailErr( MemError(), err, errExit ) ;
  483.     }
  484.     ++wg->numInStorage ;
  485.  
  486. FAIL_ERR_PROC(err, errExit)
  487. END_FAIL_ERR_PROC(err)
  488. } /* MarkOrRemember */
  489.  
  490.  
  491.  
  492. /*————————————*/
  493. static OSErr        
  494. ResultDescriptor( OSLToken *result, WHG *wg )
  495. {
  496.     long                  i ;
  497.     OSLTokenPtr         nextDesc ;
  498.     OSErr err = noErr ;
  499.  
  500.     if ( wg->mark )
  501.     {
  502.         *result = wg->markToken ;
  503.     }
  504.     
  505.     else
  506.     {
  507.         if ( (wg->numInStorage == 1) && !wg->mustReturnList )
  508.             *result = **(wg->theDescArrayH) ;
  509.         else
  510.         {
  511.             FailErr( AECreateList( NULL, 0, false, &wg->tempList ), err, errExit ) ;
  512.             
  513.             /* <eeh> here we put the tokens into a recognizable form -- an AEList.
  514.               BUT NOTE: we are creating copies of the app's tokens.  if ( we do not
  515.               dispose of the descriptors after putting them in the list they will
  516.               live in memory forever, yet to dispose is to say to the app that
  517.               we are done with them when in fact we are not.
  518.               So call AEDisposeDesc on them.  The app can dispose of them correctly
  519.               (as tokens) when it gets the resulting list back. */
  520.             
  521.             HLock( (Handle)wg->theDescArrayH ) ;
  522.             nextDesc = *(wg->theDescArrayH) ;
  523.             for( i = 1;  i <= wg->numInStorage; ++i )
  524.             {
  525.                 FailErr( AEPutDesc( &wg->tempList, i, nextDesc ), err, errExit ) ;
  526.                 IgnoreOSErr( AEDisposeDesc( nextDesc ) ) ;
  527.                 ++nextDesc ;
  528.             }
  529.  
  530.             *result = wg->tempList ;
  531.         }
  532.  
  533.         DisposeHandle( (Handle)wg->theDescArrayH ) ;
  534.     }
  535.  
  536. FAIL_ERR_PROC(err, errExit)
  537. END_FAIL_ERR_PROC(err)
  538. } // ResultDescriptor
  539.  
  540.  
  541.  
  542.  
  543. ////////////////////////////////////////////////////////////////////////////////////
  544. // AfterFirst()
  545. // determines whether a given n is >== the start of the range of
  546. // successes desired
  547. ////////////////////////////////////////////////////////////////////////////////////
  548. #define ABS(n)    ((n)>=0?(n):-(n))
  549. static Boolean
  550. AfterFirst( long n, WHG *wg )
  551. {
  552.     Boolean rval =  true ;
  553.     
  554.     //WITH (*w)->index DO
  555.     {
  556.         indexRecordPtr ip = &(*(wg->w))->index ;
  557.         if ( (ip->startCase == typeLongInteger) )
  558.         {
  559.             if ( wg->goingBackward )
  560.                 rval =  ABS(n) >= ABS(ip->stopValue) ;
  561.             else
  562.                 rval =  ABS(n) >= ABS(ip->startValue) ;
  563.         }
  564.     }
  565.     return rval ;
  566. }
  567.  
  568.  
  569. ////////////////////////////////////////////////////////////////////////////////////
  570. // BeforeLast()
  571. // determines whether a given n is <= the end of the range of successes
  572. // desired
  573. ////////////////////////////////////////////////////////////////////////////////////
  574. static Boolean
  575. BeforeLast( long n, WHG *wg )
  576. {
  577.     Boolean rval =  true ;
  578.     
  579.     // WITH (*w)->index DO
  580.     {
  581.         indexRecordPtr ip = &(*(wg->w))->index ;
  582.         if ( (ip->stopCase == typeLongInteger)    )
  583.         {
  584.             if ( n >= 0 )                /* we are counting up: use stop as last */
  585.             {
  586.                 if ( ip->stopValue > 0 )
  587.                     rval =  n <= ip->stopValue ;
  588.                 else
  589.                     rval =  true ;        /* we have to save all of them above start to do negative index */
  590.             }
  591.             else                                    /* we are counting down: use start as last -- MUST be negative */
  592.                 rval =  n >= ip->startValue ;        /* both are negative */
  593.         }
  594.     }
  595.     return rval ;
  596. }
  597.  
  598. ////////////////////////////////////////////////////////////////////////////////////
  599. // ResolveSingle()
  600. ////////////////////////////////////////////////////////////////////////////////////
  601.  
  602.  
  603. static long
  604. Middle( long n )
  605. {
  606.     return n+1 >> 1 ;        // better than BITSHIFT and DIV 2
  607. }
  608.  
  609. extern long MyLongMod( long l1, long l2) ;
  610.  
  611. // Choose a random number from 1 to n
  612. static long
  613. JRandomNumber( long n )
  614. {
  615.     long randomLong ;
  616.     if ( n != 0 )
  617.     {
  618.         randomLong = ((long)Random()) << 16 ;
  619.         randomLong |= Random() ;
  620. //        return ABS( MyLongMod( randomLong, n ) ) + 1 ;
  621.         randomLong %= n ;
  622.         return (randomLong >= 0? randomLong : -randomLong ) + 1;
  623.     }
  624.     else
  625.         return 0 ;
  626. }
  627.  
  628. static OSErr
  629. ResolveSingle( DescType theCase, long *result, WHG *wg ) 
  630. {
  631.     OSErr err = noErr ;
  632.  
  633.     if ( theCase == kAEMiddle )
  634.         *result = Middle( wg->nSuccesses ) ;
  635.     else if ( theCase == kAEAny )
  636.         *result = JRandomNumber( wg->nSuccesses ) ;
  637.     else
  638.         FailErr( errAEImpossibleRange, err, errExit ) ;
  639.  
  640. FAIL_ERR_PROC(err, errExit)
  641. END_FAIL_ERR_PROC(err)
  642. } // ResolveSingle
  643.  
  644. ////////////////////////////////////////////////////////////////////////////////////
  645. // ResolveToInteger()
  646. ////////////////////////////////////////////////////////////////////////////////////
  647. static OSErr
  648. ResolveToInteger( long *realStart, long *realStop, WHG *wg )
  649. {
  650.     OSErr err = noErr ;
  651.  
  652.     // WITH (*w)->index DO            /* EvalWhose locks the whose record down */
  653.     {
  654.         indexRecordPtr ip = &(*(wg->w))->index ;
  655.         
  656.         if ( wg->hasRelative && !wg->isARange )            /* isn't going backward, and will have saved all successes;
  657.                                                                         no longs or negative longs (UNLESS marking is in use!!!) */
  658.         {
  659.             if ( ip->startCase == kAEAll )
  660.             {
  661.                 *realStart = 1 ;
  662.                 *realStop = wg->numInStorage ;        /* same as wh->nSuccesses */
  663.             }
  664.             else if ( ip->startCase == typeLongInteger )        /* only possible if ( we're doing marking,... */
  665.             {                                                                            /* ...which will have caused us to save all successes */
  666.                 if ( ip->startValue > 0 )
  667.                     *realStart = ip->startValue ;
  668.                 else
  669.                     *realStart = wg->numInStorage + ip->startValue + 1 ;
  670.                 *realStop = *realStart ;
  671.             }
  672.             else 
  673.             {        /* any, middle */
  674.                 long temp ;
  675.                 FailErr( ResolveSingle( ip->startCase, &temp, wg ), err, errExit ) ; 
  676.                 *realStop = *realStart = temp ;
  677.             }
  678.         }
  679.         else if ( wg->isARange )
  680.         {
  681.             if ( ip->startCase == typeLongInteger )
  682.             {
  683.                 if ( (ip->startValue > 0) || wg->goingBackward )
  684.                     *realStart = 1 ;
  685.                 else
  686.                     *realStart = wg->numInStorage + ip->startValue + 1 ;
  687.             }
  688.             else
  689.             {        /* any, middle */
  690.                 long temp ;
  691.                 FailErr( ResolveSingle( ip->startCase, &temp, wg ), err, errExit ) ; 
  692.                 *realStart = temp ;
  693.             }
  694.             
  695.             if ( ip->stopCase == typeLongInteger )
  696.             {
  697.                 if ( ip->stopValue >= 0 )
  698.                 {
  699.                     if ( ip->startValue >= 0 )    
  700.                         *realStop = ip->stopValue - ip->startValue + 1 ;
  701.                     else
  702.                         *realStop = ip->stopValue ;
  703.                 }
  704.                 else
  705.                 {
  706.                     if ( ip->stopValue >= 0 )    
  707.                         *realStop = wg->numInStorage + ip->stopValue + 1 ;
  708.                     else if ( wg->goingBackward )            // same as IF mark THEN
  709.                         *realStop = wg->numInStorage ;
  710.                     else
  711.                         *realStop = wg->numInStorage + ip->stopValue + 1; /* added 4/1 */
  712.                 }
  713.             }
  714.             else        /* any, middle */
  715.             {
  716.                 long temp ;
  717.                 FailErr( ResolveSingle( ip->stopCase, &temp, wg ), err, errExit ) ; 
  718.                 *realStop = temp ;
  719.             }
  720.         }
  721.         else                /* must be a single index; positive or negative doesn't matter, as there should */
  722.         {            /*    be only one in storage anyway.  if ( there aren't any in storage, we've an */
  723.             if ( wg->numInStorage == 1 )                    /* error.  Get the 3nd n when there are only 2 ns will */
  724.             {                                                        /* produce such a case.            */
  725.                 *realStart = *realStop = 1 ;
  726.             }
  727.             else
  728.             {
  729.     //            PAssert( wg->numInStorage == 0, 'wg->numInStorage != 0' ) ;
  730.                 FailErr( errAENoSuchObject, err, errExit ) ;
  731.             }
  732.         }
  733.     }        /*with*/
  734.  
  735. FAIL_ERR_PROC(err, errExit)
  736. END_FAIL_ERR_PROC(err)
  737. } /* ResolveToInteger*/
  738.             
  739.  
  740.  
  741.  
  742.     /*———————————————————————— EvalWhose ————————————————————————*/
  743. /*evaluates a Whose term*/
  744.  
  745. OSErr
  746. EvalWhose( Whose whoz , DescType  wantClass , DescType  containerClass ,
  747.         OSLToken  container , short appDoesFlags )
  748. {
  749.     long         nElements ;
  750.     long         realStart ;
  751.     long         realStop ;
  752.     AEDesc         dIth ;            /* descriptor holding selection data for i-th element */
  753. //    long         i ;
  754.     OSLToken     dThisElement ;
  755. //    AEDesc         tempList ;            /* used where more than one result to be returned; dispose only on error */
  756. //    AEDesc         markToken ;            /* change markID to descriptor 1/10; dispose only in FailErr */
  757. //    DescArrayHandle          theDescArrayH ;
  758. //    long          nSuccesses ;
  759. //    long          numInStorage ;            /* used for marked case and unmarked: always <== nSuccesses, as excluded those cases outside of range */
  760.     long          searchStart ;
  761.     long          searchEnd ;
  762.     long          incrementer ;
  763. //    Boolean          isARange ;
  764. //    Boolean          isFromEnd ;
  765. //    Boolean          hasRelative ;
  766. //    Boolean          mark ;
  767. //    Boolean          goingBackward ;
  768. //    Boolean          mustReturnList ;
  769.     WHG                whg ;
  770.     OSErr err = noErr;
  771. #define USE_TEMP_CONTEXT_CHANGE
  772. #ifdef USE_TEMP_CONTEXT_CHANGE
  773.     OSLContext savedCurContext;
  774. #endif
  775.  
  776.     whg.w = whoz ;
  777. #ifndef MARKING_FIX
  778.     whg.mark = (appDoesFlags & kAEIDoMarking) != 0 ;
  779. #endif
  780.     MakeNullToken( &whg.markToken ) ;
  781.     MakeNullToken( &dThisElement ) ;
  782.     whg.nSuccesses = 0 ;
  783.     whg.tempList.dataHandle = NULL ;
  784.     dIth.dataHandle = NULL ;
  785.     whg.theDescArrayH = NULL ;
  786.  
  787.     HLock( (Handle)whg.w ) ;
  788.  
  789.     // WITH whg.w** DO
  790.     {
  791.         WhoseRecordPtr wp = *whg.w ;
  792.         whg.isARange = wp->index.stopCase != typeNull;    // are we looking 
  793.                                                     // for a range or one?
  794.         
  795.         if ( whg.isARange )
  796.         //WITH index DO
  797.         {
  798.             indexRecordPtr ip = &wp->index ;
  799.             if ( ip->stopCase == typeLongInteger )
  800.                 if ( ip->startCase == typeLongInteger )
  801.                     if ( (ip->startValue > 0) && (ip->stopValue > 0)
  802.                             && (ip->startValue > ip->stopValue)
  803.                             || ((ip->startValue < 0) && (ip->stopValue < 0)
  804.                             && (ip->startValue > ip->stopValue)) )
  805.                         FailErr( errAEImpossibleRange, err, errExit ) ;
  806.         }
  807.     
  808.         FailErr( NewCallCountProc( wantClass, containerClass, container,
  809.                 &nElements ), err, errExit ) ;
  810.                 
  811.         // This code would prevent infinite loop/crash for case where 
  812.         // CallCountProc returns negative value.
  813.         
  814.         if ( nElements < 0 )                    /* equal to 0 may be ok: may want to return empty list rather than error */
  815.             FailErr( errAENegativeCount, err, errExit ) ;
  816.         
  817. #ifndef MARKING_FIX
  818.         // moved to InitMarking (above)
  819.         if ( whg.mark )
  820.         {
  821.             FailErr( NewCallGetMarkToken( container, containerClass, &whg.markToken ),
  822.                     err, errExit ) ;
  823.         }
  824.         else
  825.         {
  826.             whg.theDescArrayH = (OSLTokenHandle)NewHandle( 0 ) ; /* sizeof(AEDesc) )) ;*/
  827.             FailErr( MemError(), err, errExit ) ;
  828.         }
  829. #endif
  830.         whg.numInStorage = 0 ;
  831.  
  832. #ifndef MARKING_FIX
  833.         // we cannot iterate backwards because we don't know if we are going to
  834.         // be marking until we try to MarkOrRemember something.
  835.         
  836.         /* We can iterate backwards for advantage iff 1) not using marking, and 
  837.         2) it is either a negative index or
  838.         a range composed of two negative indices */
  839.         
  840.         whg.goingBackward = (! whg.mark)
  841.                 && (wp->index.startCase == typeLongInteger)
  842.                 && (wp->index.startValue < 0)
  843.                 && ((wp->index.stopCase == typeNull) 
  844.                         || ((wp->index.stopCase == typeLongInteger)
  845.                                 && (wp->index.stopValue < 0))) ;                    
  846. #else
  847.         whg.goingBackward = false;
  848. #endif
  849.         
  850.         whg.mustReturnList = wp->index.startCase == kAEAll ;
  851.         
  852.         // hasRelative really means 'mustStoreAll'; hence it includes the case where
  853.         // we're looking for the -2nd and would be going backwards if mark weren't
  854.         // true
  855.         
  856.         whg.hasRelative = whg.mustReturnList    // was (index.startCase = kAEAll)
  857. #ifndef MARKING_FIX
  858.                 // this clause can't be evaluated since we don't know if marking is on yet
  859.                 || ((wp->index.startCase == typeLongInteger) && (wp->index.startValue < 0)
  860.                     && ((wp->index.stopCase == typeNull)
  861.                         || ((wp->index.stopCase == typeLongInteger)
  862.                             && (wp->index.stopValue < 0)))
  863.                     && whg.mark)
  864. #endif
  865.                 || (wp->index.startCase == kAEAny)
  866.                 || (wp->index.stopCase == kAEAny)
  867.                 || (wp->index.startCase == kAEMiddle)
  868.                 || (wp->index.stopCase == kAEMiddle) ; // tests for  gross cases where 
  869.                                                   // each and every matching element 
  870.                                                   // must be marked or remembered
  871.         
  872.     //                || ((index.startCase == typeLongInteger) && (index.start < 0))
  873.     //                || ((index.stopCase == typeLongInteger) && (index.stop < 0)) ;
  874.         
  875.         // initialize a handy ith element descriptor
  876.         FailErr( AECreateDesc( typeLongInteger, NULL, sizeof(long), &dIth ),
  877.                 err, errExit ) ;
  878.         
  879.         /*
  880.         (relatively) unoptimized whose clause evaluation: ask the app how many of a given class
  881.         it has in the container, and loop through getting each by index and testing.  For those
  882.         that pass: record another success, and check if we are dealing with a range or
  883.         relative.  if a range we don't need to record those that are before or after.  if an
  884.         index we know exactly which we are after and when we're done.
  885.         
  886.         One optimization added: if ( we are after the last n passing the test, we never keep
  887.         track of more than the last n to pass the test.
  888.         */
  889.         if ( whg.goingBackward )
  890.         {
  891.             searchStart = nElements ;
  892.             searchEnd = 0 ;
  893.             incrementer = -1 ;
  894.         }
  895.         else    
  896.         {
  897.             searchStart = 1 ;
  898.             searchEnd = nElements + 1 ;
  899.             incrementer = 1 ;
  900.         } 
  901.     
  902. #ifdef USE_TEMP_CONTEXT_CHANGE
  903.         FailErr( GetCurrentContext( &savedCurContext ), err, errExit );
  904. #endif
  905.  
  906.         while ( searchStart != searchEnd )
  907.         {
  908.             // Get the ith element as objBeingExamined for term
  909.             **(long **)dIth.dataHandle = searchStart ;
  910. #ifdef USE_TEMP_CONTEXT_CHANGE
  911.             // <eeh> added: start each resolution with the same context.
  912.             SetCurrentContext(&savedCurContext);            
  913. #endif
  914.             FailErr( iCallAccessor( wantClass, container, containerClass,
  915.                     formAbsolutePosition, dIth, &dThisElement), err,
  916.                     errExit) ;
  917.             
  918.             // evaluate the term. dThisElement is exmn
  919.             FailErr( EvalTerm( wp->theTerm, wantClass, &dThisElement, appDoesFlags ),
  920.                     err, errExit ) ;
  921.             
  922.             if ( (*(wp->theTerm))->value )
  923.             {
  924.                 whg.nSuccesses += incrementer ;
  925.                 
  926.                 // since could be both a range and relative ("from the second
  927.                 // to the last"), do relative first.  Range will sometimes ignore
  928.                 // cases (those not afterFirst or beforeLast) that need to be 
  929.                 // considered if ( a relative is also involved.
  930.                 
  931.                 if ( whg.hasRelative )
  932.                 {
  933.                     FailErr( MarkOrRemember( dThisElement, whg.nSuccesses, containerClass, container, &whg ),
  934.                             err, errExit ) ;
  935.                 }
  936.                 else if ( whg.isARange )
  937.                 {
  938.                     if ( AfterFirst(whg.nSuccesses, &whg) )
  939.                     {
  940.                         if ( BeforeLast( whg.nSuccesses, &whg ) )
  941.                         {
  942.                             //<eeh> this won't work for whg.nSuccesses < 0
  943.                             FailErr( MarkOrRemember( dThisElement,
  944.                                     whg.nSuccesses-(wp->index.startValue-1), containerClass, container, &whg ),
  945.                                     err, errExit ) ;        
  946.                         }
  947.                         else
  948.                         {
  949.                             whg.nSuccesses -= incrementer ;        // 3/18; back down if ( we don't need this one
  950.                             FailErr( iAEDisposeToken( &dThisElement ),
  951.                                     err, errExit ) ;// 3/23 dispose of it too!
  952.                             break ;            // if ( after last, we are done with this whose
  953.                         }
  954.                         // above because can't put 2nd desc if no 1st
  955.                     }
  956.                     else
  957.                     {
  958.                         FailErr( iAEDisposeToken( &dThisElement ), err, errExit ) ;
  959.                     }
  960.                 }
  961.                 else        // it's a simple index
  962.                 {
  963.                     if ( whg.nSuccesses == wp->index.startValue )
  964.                     {
  965.                         // it is the first, by definition
  966.                         FailErr( MarkOrRemember( dThisElement, 1, containerClass, container, &whg ),
  967.                                 err, errExit ) ;
  968.                         break ;                    // we got it; get out of for loop 
  969.                     }
  970.                     else
  971.                         FailErr( iAEDisposeToken( &dThisElement ), err, errExit ) ;
  972.                 }
  973.             }
  974.             else
  975.                 FailErr( iAEDisposeToken( &dThisElement ), err, errExit ) ;
  976.             
  977.             searchStart += incrementer ;
  978.         } // while
  979.     
  980.         if ( (whg.nSuccesses == 0) && !whg.mustReturnList )    // was <= 0; fixes LLD-UPG-25
  981.             FailErr( errAENoSuchObject, err, errExit ) ;    // fixes LLD-UPG-22 bug: was invalidRelative
  982.         
  983.         FailErr( ResolveToInteger( &realStart, &realStop, &whg ),
  984.                 err, errExit ) ;
  985.         FailErr( RedoListOrMark( realStart, realStop, &whg ), err, errExit ) ;
  986.         
  987.         FailErr( ResultDescriptor( &wp->whoseValue, &whg ), err, errExit) ;
  988.         
  989.         IgnoreOSErr( AEDisposeDesc( &dIth ) );
  990.     
  991.     } // WITH
  992.     HUnlock((Handle)whg.w);
  993.  
  994.  
  995.  
  996.  
  997. FAIL_ERR_PROC(err, errExit)
  998.     long  i ;
  999.     if ( (whg.w != NULL) && (SetErrDesc( (*whg.w)->theWhoseInput )) )                /* 4/5. So doesn't dispose later */
  1000.         (*whg.w)->theWhoseInput.dataHandle = NULL ;
  1001.     IgnoreOSErr( AEDisposeDesc( &dIth ) );
  1002.     IgnoreOSErr( InternalDisposeToken( &whg.tempList ) );
  1003.     IgnoreOSErr( iAEDisposeToken( &dThisElement ) ) ;
  1004.  
  1005.     if ( whg.mark )
  1006.         IgnoreOSErr( iAEDisposeToken( &whg.markToken ) ) ;
  1007.     else if ( whg.theDescArrayH != NULL )
  1008.     {
  1009.         for( i = 0; i <= whg.numInStorage-2; ++i )    // 1 because 0-based; another because the i-1th is dThisElement, disposed above */
  1010.         {
  1011.             IgnoreOSErr( iAEDisposeToken( &(*(whg.theDescArrayH))[i] ) ) ;
  1012.         }
  1013.         DisposeHandle( (Handle)whg.theDescArrayH ) ;
  1014.     }
  1015. END_FAIL_ERR_PROC(err)
  1016.  
  1017.  
  1018. } // EvalWhose
  1019.  
  1020.  
  1021.